package org.example;

import redis.clients.jedis.*;
import redis.clients.jedis.params.SetParams;

import java.util.*;

/**
 * Redis客户端操作类
 * 封装基础命令和分布式锁操作
 *
 * @author fxab
 * @date 2025/04/06
 */
public class RedisClient {
    private final ConnectionConfig config;

    /**
     * redis客户端
     *
     * @param config 配置
     */
    public RedisClient(ConnectionConfig config) {
        this.config = config;
    }

    //------------------------ 基础命令实现 ------------------------//

    /**
     * redis的SET命令实现
     *
     * @param key    键
     * @param value  值
     * @param params 参数（NX/EX等）
     * @return {@link String }
     */
    public String set(String key, String value, SetParams params) {
        try {
            if (config.getMode() == ConnectionConfig.Mode.CLUSTER) {
                return config.getCluster().set(key, value, params);
            }
            try (Jedis jedis = config.getResource()) {
                return jedis.set(key, value, params);
            }
        } catch (Exception e) {
            throw new RedisException("SET操作失败: " + key, e);
        }
    }

    /**
     * redis的GET命令实现
     *
     * @param key 键
     * @return {@link String }
     */
    public String get(String key) {
        try {
            if (config.getMode() == ConnectionConfig.Mode.CLUSTER) {
                return config.getCluster().get(key);
            }
            try (Jedis jedis = config.getResource()) {
                return jedis.get(key);
            }
        } catch (Exception e) {
            throw new RedisException("GET操作失败: " + key, e);
        }
    }

    /**
     * MGET命令实现（集群模式特殊处理）
     *
     * @param keys 键列表
     * @return {@link List }<{@link String }>
     */
/*    public List<String> mget(String... keys) {
        try {
            if (config.getMode() == ConnectionConfig.Mode.CLUSTER) {
                // 集群模式需逐个获取
                List<String> results = new ArrayList<>(keys.length);
                for (String key : keys) {
                    results.add(config.getCluster().get(key));
                }
                return results;
            }
            try (Jedis jedis = config.getResource()) {
                return jedis.mget(keys);
            }
        } catch (Exception e) {
            throw new RedisException("MGET操作失败", e);
        }
    }*/

    /**
     * redis的DEL命令实现
     *
     * @param keys 要删除的键
     * @return {@link Long }
     */
    public Long del(String... keys) {
        try {
            if (config.getMode() == ConnectionConfig.Mode.CLUSTER) {
                // 集群模式返回删除总数
                long total = 0;
                for (String key : keys) {
                    total += config.getCluster().del(key);
                }
                return total;
            }
            try (Jedis jedis = config.getResource()) {
                return jedis.del(keys);
            }
        } catch (Exception e) {
            throw new RedisException("DEL操作失败", e);
        }
    }


    /**
     * 尝试获取锁
     *
     * @param key   锁键
     * @param value 唯一标识（建议UUID）
     * @param ttl   锁有效期（秒）
     * @return boolean
     */
    public boolean tryLock(String key, String value, int ttl) {
        SetParams params = SetParams.setParams().nx().ex(ttl);
        return "OK".equals(set(key, value, params));
    }

    /**
     * 释放锁（Lua脚本保证原子性）
     *
     * @param key   锁键
     * @param value 唯一标识
     * @return boolean
     */
    public boolean unlock(String key, String value) {
        String script =
                "if redis.call('get', KEYS[1]) == ARGV[1] then " +
                        "    return redis.call('del', KEYS[1]) " +
                        "else " +
                        "    return 0 " +
                        "end";

        try {
            Object result;
            if (config.getMode() == ConnectionConfig.Mode.CLUSTER) {
                result = config.getCluster().eval(script, 1, key, value);
            } else {
                try (Jedis jedis = config.getResource()) {
                    result = jedis.eval(script, Collections.singletonList(key), Collections.singletonList(value));
                }
            }
            return result.equals(1L);
        } catch (Exception e) {
            throw new RedisException("解锁失败: " + key, e);
        }
    }

    /**
     * 检查Redis是否可用
     *
     * @return boolean
     */
    public boolean isAvailable() {
        try {
            if (config.getMode() == ConnectionConfig.Mode.CLUSTER) {
                return !config.getCluster().getClusterNodes().isEmpty();
            } else {
                try (Jedis jedis = config.getResource()) {
                    return "PONG".equals(jedis.ping());
                }
            }
        } catch (Exception e) {
            return false;
        }
    }


    public static class RedisException extends RuntimeException {
        public RedisException(String message, Throwable cause) {
            super(message, cause);
        }
    }

    /**
     * 关闭客户端连接
     */
    public void close() {
        config.close();
    }
}